using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;

namespace SynoManager.DownloadStation
{
    /// <summary>
    /// Class that contains all plugins for the <seealso cref="DownloadStationService" />.
    /// </summary>
    public class DownloadStationPluginManager : TypeAttributeManager<IDownloadStationPlugin, DownloadStationPluginAttribute>
    {
        private List<IDownloadStationPlugin> instances;
        protected override void AfterRebuild()
        {
            instances = new List<IDownloadStationPlugin>();
            foreach(Type type in Types)
            {
                IDownloadStationPlugin plugin = (IDownloadStationPlugin) Activator.CreateInstance(type);
                instances.Add(plugin);
            }
        }

        /// <summary>
        /// Initialize all the plugins with the specified service.
        /// </summary>
        /// <param name="service">Service</param>
        /// <remarks>
        /// Calls the <seealso cref="IDownloadStationPlugin.Initialize(DownloadStationService)"/> method on all plugins.
        /// </remarks>
        public void Initialize(DownloadStationService service)
        {
            foreach(var instance in AllPlugins)
                instance.Initialize(service);
        }

        /// <summary>
        /// Get an instance of a plugin with the specified type.
        /// </summary>
        /// <param name="type"><see cref="Type"/> of plugin to get.</param>
        /// <returns>Instance of plugin.</returns>
        public new IDownloadStationPlugin this[Type type]
        {
            get
            {
                foreach (var plugin in instances)
                {
                    if (plugin.GetType() == type)
                        return plugin;
                }
                return null;
            }
        }

        /// <summary>
        /// Close all plugins.
        /// </summary>
        /// <remarks>
        /// Calls the <seealso cref="IDownloadStationPlugin.Close()"/> method on all plugins.
        /// </remarks>
        public void Close()
        {
            foreach(var instance in AllPlugins)
                instance.Close();
        }

        /// <summary>
        /// Gets the enumerator for all plugins.
        /// </summary>
        public IEnumerable<IDownloadStationPlugin> AllPlugins
        {
            get { return instances; }
        }

        #region File Handler
        /// <summary>
        /// Gets all plugins that are capable of file handling
        /// </summary>
        /// <seealso cref="IDownloadFileHandlerPlugin" />
        public IEnumerable<IDownloadFileHandlerPlugin> FileHandlers
        {
            get { return instances.OfType<IDownloadFileHandlerPlugin>(); }
        }

        /// <summary>
        /// Process a new file which is to be added to the Download Station.
        /// </summary>
        /// <param name="args">Arguments for the new <see cref="DownloadTask" />.</param>
        public void Process(ProcessFileArgs args)
        {
            foreach(var fileHandler in FileHandlers)
            {
                if (fileHandler.CanProcess(args.Path))
                {
                    fileHandler.Process(args);
                    if (args.Cancel || args.Processed)
                        return;
                }
            }
        }
        #endregion

        #region URL Handlers
        /// <summary>
        /// Gets the list of all <seealso cref="IDownloadUrlProtocolHandlerPlugin" /> plugins
        /// </summary>
        public IEnumerable<IDownloadUrlProtocolHandlerPlugin> UrlProtocolHandlers
        {
            get { return instances.OfType<IDownloadUrlProtocolHandlerPlugin>(); }
        }

        /// <summary>
        /// Gets the list of all <seealso cref="IDownloadUrlHandlerPlugin" /> plugins
        /// </summary>
        public IEnumerable<IDownloadUrlHandlerPlugin> UrlHandlers
        {
            get { return instances.OfType<IDownloadUrlHandlerPlugin>(); }
        }

        /// <summary>
        /// Gets the list of all <seealso cref="IDownloadWebHandlerPlugin" /> plugins
        /// </summary>
        public IEnumerable<IDownloadWebHandlerPlugin> WebHandlers
        {
            get { return instances.OfType<IDownloadWebHandlerPlugin>(); }
        }

        /// <summary>
        /// Process a new url which is to be added to the Download Station.
        /// </summary>
        /// <param name="args">Arguments for the new <see cref="DownloadTask" />.</param>
        public void Process(ProcessUrlArgs args)
        {
            foreach (var handler in UrlHandlers)
            {
                handler.Process(args);
                if (args.Cancel || args.Processed)
                    return;
            }

            /*HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(args.Url);
            request.Method = "HEAD";
            HttpWebResponse response = (HttpWebResponse) request.GetResponse();
            args.Response = response;
            foreach(var handler in WebHandlers)
            {
                handler.Process(args);
                if (args.Cancel)
                    return;
            }*/

            foreach(var handler in UrlProtocolHandlers)
            {
                if (args.Url.Scheme == handler.ProtocolPrefix)
                {
                    handler.Process(args);
                    if (args.Cancel || args.Processed)
                        return;
                }
            }
        }
        #endregion
       
        #region Task Plugins
        /// <summary>
        /// Gets the list of all <seealso cref="IDownloadTaskPlugin" /> plugins
        /// </summary>
        public IEnumerable<IDownloadTaskPlugin> TaskPlugins
        {
            get { return instances.OfType<IDownloadTaskPlugin>(); }
        }

        /// <summary>
        /// Function that is called when a new <see cref="DownloadTask" /> is added to the Download Station.
        /// </summary>
        /// <remarks>Calls the <seealso="IDownloadTaskPlugin.OnTaskAdded(DownloadTask)" /> on all plugins</remarks>
        /// <param name="task">Newly added <see cref="DownloadTask" />.</param>
        public void OnTaskAdded(DownloadTask task)
        {
            foreach(var plugin in TaskPlugins)
                plugin.OnTaskAdded(task);
        }

        /// <summary>
        /// Function that is called when a <see cref="DownloadTask" /> was updated on the Download Station.
        /// </summary>
        /// <remarks>Calls the <seealso="IDownloadTaskPlugin.OnTaskUpdate(DownloadTask)" /> on all plugins</remarks>
        /// <param name="task">Updated <see cref="DownloadTask" />.</param>
        public void OnTaskUpdate(DownloadTask task)
        {
            foreach(var plugin in TaskPlugins)
                plugin.OnTaskUpdate(task);
        }

        /// <summary>
        /// Function that is called when the <seealso cref="DownloadTask.State" /> of a <see cref="DownloadTask" /> changed on the Download Station.
        /// </summary>
        /// <remarks>Calls the <seealso="IDownloadTaskPlugin.OnTaskStateChange(DownloadTask)" /> on all plugins</remarks>
        /// <param name="task">Changed <see cref="DownloadTask" />.</param>
        public void OnTaskStateChange(DownloadTask task)
        {
            foreach(var plugin in TaskPlugins)
                plugin.OnTaskStateChange(task);
        }

        /// <summary>
        /// Function that is called when a <see cref="DownloadTask" /> was removed on the Download Station.
        /// </summary>
        /// <remarks>Calls the <seealso="IDownloadTaskPlugin.OnTaskRemoved(DownloadTask)" /> on all plugins</remarks>
        /// <param name="task">Removed <see cref="DownloadTask" />.</param>
        public void OnTaskRemoved(DownloadTask task)
        {
            foreach (var plugin in TaskPlugins)
                plugin.OnTaskRemoved(task);
        }
        #endregion
    }
}